GLOBAL  _lidt
GLOBAL  int_08_hand
GLOBAL  int_09_hand
GLOBAL  int_80_hand
GLOBAL  writecmos
GLOBAL  readcmos
GLOBAL	maskPIC1, maskPIC2, _Cli, _Sti
GLOBAL  debug
GLOBAL  eoi
GLOBAL invop_hand
GLOBAL ssf_hand
GLOBAL snp_hand
GLOBAL div0_hand
GLOBAL gpf_hand
GLOBAL bounds_hand
GLOBAL pagefault_hand
GLOBAL _free_task
GLOBAL _doexit
GLOBAL _waitpid
GLOBAL _hacersnp
GLOBAL _hacerbounds
GLOBAL _hacergpf
GLOBAL _hacerssf
GLOBAL _hacerinvop
GLOBAL 	_lgdt
GLOBAL read_cr0
GLOBAL write_cr0
GLOBAL read_cr3
GLOBAL write_cr3
GLOBAL _DelCursor
GLOBAL _RestoreCursor
GLOBAL _inb
GLOBAL _Lights

EXTERN int_08
EXTERN int_09
EXTERN free_task
EXTERN exit_task
EXTERN waitpid
EXTERN switch_console
EXTERN get_task_child_status
EXTERN invop
EXTERN div0
EXTERN gpf
EXTERN ssf
EXTERN snp
EXTERN bounds
EXTERN pfault

SECTION .text

_Cli:
	cli			; limpia flag de interrupciones
	ret

_Sti:

	sti			; habilita interrupciones por flag
	ret

read_cr0:
	mov eax, cr0
	retn

write_cr0:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr0,  eax
	pop ebp
	retn

read_cr3:
	mov eax, cr3
	retn

write_cr3:
	push ebp
	mov ebp, esp
	mov eax, [ebp+8]
	mov cr3, eax
	pop ebp
	retn


maskPIC1:			; Escribe mascara del PIC 1
	push    ebp
        mov     ebp, esp
        mov     ax, [ss:ebp+8]  ; ax = mascara de 16 bits
        out	21h,al
        pop     ebp
        retn

maskPIC2:			; Escribe mascara del PIC 2
	push    ebp
        mov     ebp, esp
        mov     ax, [ss:ebp+8]  ; ax = mascara de 16 bits
        out	0A1h,al
        pop     ebp
        retn


_lidt:				; Carga el IDTR
        push    ebp
        mov     ebp, esp
        push    ebx
        mov     ebx, [ss: ebp + 6] ; ds:bx = puntero a IDTR
		rol	ebx,16
		lidt    [ds: ebx]          ; carga IDTR
        pop     ebx
        pop     ebp
        retn

_lgdt:   ; Carga el GDTR
		push    ebp
        mov     ebp, esp
        push    ebx
        mov     ebx, [ss: ebp + 6] ; ds:bx = puntero a GDTR
		rol	ebx,16
		lgdt    [ds: ebx]         ; carga GDTR
        pop     ebx
        pop     ebp
        retn

_hacersnp:
;	push 0x30
;	pop ds
	retn

_hacergpf:
	mov ax, 77
	mov ds, ax
	retn

_hacerssf:
	mov ax, 0x30
	mov ss, ax
	retn

_hacerbounds:
	mov ax, 100
	bound ax, [0x1234]
	retn

_hacerinvop:
	mov ebx, 0xC8C70FF0
	mov [0x123456], ebx
	jmp 0x123456

div0_hand:				; Handler de excepcion "Divide by zero"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call div0
	mov al,20h			; Envio de EOI generico al PIC
	out 20h,al
	popf
	popa
	pop es
	pop ds
	;jmp $
	iret

bounds_hand:			; Handler de excepcion "BOUND range exceeded"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call bounds
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop es
	pop ds
	jmp $
	iret

gpf_hand:				; Handler de excepcion "General protection exception"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov eax, 666666h
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call gpf
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	jmp $
	iret

ssf_hand:				; Handler de excepcion "Stack exception"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call ssf
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	jmp $
	iret

snp_hand:				; Handler de excepcion "Segment not present"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call snp
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	jmp $
	iret

invop_hand:				; Handler de excepcion "Invalid opcode"
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call invop
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	pop ax
	popa
	pop ax
	pop ax
	jmp $
	iret

pagefault_hand:
	push ds
	push es				; Se salvan los registros
	pusha				; Carga de DS y ES con el valor del selector
	pushf
	mov ax, 10h			; a utilizar.
	mov ds, ax
	mov es, ax
	call pfault
	mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popf
	popa
	pop ax
	pop ax
	;jmp $
	iret

int_08_hand:	
	call _Cli  			; Handler de INT 8 ( Timer tick)
    push    ds
    push    es                      ; Se salvan los registros
    pushad                           ; Carga de DS y ES con el valor del selector
    mov     ax, 10h			; a utilizar.
    mov     ds, ax
    mov     es, ax
    call    int_08
    mov	al,20h			; Envio de EOI generico al PIC
	out	20h,al
	popad
    pop     es
    pop     ds
    call _Sti  
    iret


int_09_hand:
	cli  
	pushad
	pushfd
	mov	eax, 0
	in	al, 60h		; Leo el puerto de teclado.
	push	eax		; Pongo el scancode en el stack.
	call	int_09		; Invoco a una funcion de C.
	push	eax		; int_09 devolvio el numero de terminal
				; a la que hay que cambiar, en eax.
	
	call    switch_console	; Cambio de terminal (de ser necesario).
	
	pop	eax		; saco la terminal del stack
	pop	eax		; saco el scancode del stack
	popfd
	popad
	sti  
	iret

eoi:
	push ax			; Resguardar al
	mov 	al, 20h
	out	20h, al		; Envio el EOI al PIC.
	pop ax			; Restaurar al
	ret

int_80_hand:				; Handler de INT 80 ( write)
        
    call _Cli                     
    push    ds
    push    es
    pushad

	cmp ebx, 1
	jz  freet
	cmp ebx, 2
	jz  ext
	cmp ebx, 3
	jz  wt
	
freet: 
	push    edx             ; status 
	push    ecx             ; pid
    call    free_task
  
    pop     edx
    pop     ecx
	jmp end
	
ext: 
	push ecx	
	call exit_task
	
	pop     ecx
	jmp end
	
wt: 
	push ecx	
	call waitpid
	
	pop ecx
	jmp end
		
	;mov	al,20h			; Envio de EOI generico al PIC
	;out	20h,al
	
end:popad
    pop     es
    pop     ds
    call _Sti                    
    iret


_free_task:
	push    ebp             ; stack frame
    mov     ebp, esp

    mov     ebx, 1
    mov     ecx, [ebp+8]    
    mov     edx, [ebp+12]   

    int     080h

    mov     esp, ebp        
    pop     ebp
    ret
    
_doexit:
	push    ebp             ; stack frame
    mov     ebp, esp

    mov     ebx, 2
    mov     ecx, [ebp+8]       

    int     080h

    mov     esp, ebp        
    pop     ebp
    ret

_waitpid:
	push    ebp             ; stack frame
    mov     ebp, esp

    mov     ebx, 3
    mov     ecx, [ebp+8]       

    int     080h
	call    get_task_child_status
	
    mov     esp, ebp        
    pop     ebp
    ret
    
writecmos:
	push ebp
	mov ebp, esp
	mov eax, [ebp + 0x0c]	; al = nro. de registro del RTC donde escribir
	mov edx, [ebp + 0x08]	; dl = nro. BCD a escribir en el RTC

	and al, 7fh	; enmascarar los bits del nro. de registro
	out 70h, al	; cargar el nro. de registro del RTC
	nop
	nop		; delay
	nop
	mov al, dl	; cargar en al el BCD que esta en dl
	out 71h, al	; escribir el BCD en el registro del RTC
	and eax, 0ffh	; enmascarar eax para que el valor de retorno sea al

	pop ebp
	ret

readcmos:
	push ebp
	mov ebp, esp
	mov eax, [ebp + 0x08]	; al = nro. de registro del RTC donde leer

	and al, 7fh	; enmascarar los bits del nro. de registro
	out 70h, al	; cargar el nro. de registro del RTC
	nop
	nop		; delay
	nop
	nop
	nop
	in al, 71h	; leer el BCD del registro del RTC
	and eax, 0ffh	; enmascarar eax para que el valor de retorno sea al

	pop ebp
	ret


_inb:		
	push ebp			
    mov ebp, esp
	mov edx, [ebp+8]
	mov eax, 0
	in al, dx
	pop	ebp
	ret


_Lights:
    push	ebp
	mov		ebp, esp
	mov		al,[EBP+8]
	mov		ah,al

    cli                             ; Deshabilito interrupciones
    mov     al,0edh                 ; Cargo el Set/Reset Mode Indicator
    out     60h,al

l1: in      al,60h                  ; Espero el ACK del 8042
    cmp     al,0fah
    jnz     l1
    mov     al,ah                   ; Mando las nuevas luces
    out     60h,al
l2: in      al,60h                  ; Espero el ACK del 8042
    cmp     al,0fah
    jnz     l2
    sti                             ; habilito interrupciones de nuevo
	pop		ebp
    ret


_DelCursor:
     push     ax
     push     dx
     pusha
     mov	 bx, 0xF00				; Hago desaparecer el cursor
     mov     dx, 0x3D4
     mov     al, 0x0A
     mov     ah, bh
     out     dx, ax
     inc     ax
     mov     ah, bl
     out     dx, ax
     popa
     pop     dx
     pop     ax
     ret


_RestoreCursor:
     push     ax
     push     dx
     pusha
     mov	    bx, 0xFF0				; Vuelvo a ponerle grosor visible
     mov     dx, 0x3D4
     mov     al, 0x0A
     mov     ah, bh
     out     dx, ax
     inc     ax
     mov     ah, bl
     out     dx, ax
     popa
     pop     dx
     pop     ax
     ret

; Debug para el BOCHS, detiene la ejecucion.
; Para continuar colocar en el BOCHSDBG: set $eax=0
;

debug:
        push    ebp
        mov     ebp, esp
        push	eax
vuelve:	mov     eax, 1
        cmp	eax, 0
	jne	vuelve
	pop	eax
	pop     ebp
        ret


